#include <gtest/gtest.h>
#include "protocol/JsonRpcHandlerImpl.h"
#include "mock/MockMessageParser.h"
#include "mock/MockMessageSerializer.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QByteArray>
#include <QVariant>
#include <memory>

using ::testing::_;
using ::testing::Return;
using ::testing::NiceMock;

// Forward declarations
class JsonRpcHandlerImpl;

/**
 * @brief Unit tests for JsonRpcHandlerImpl class
 * @details Tests the JSON-RPC protocol handler implementation including
 * parsing, serialization, and error handling
 */
class TestJsonRpcHandlerImpl : public ::testing::Test
{
protected:
    void SetUp() override
    {
        mHandler = new JsonRpcHandlerImpl();
        mHandler->setMessageParser(std::make_unique<MockMessageParser>());
        mHandler->setMessageSerializer(std::make_unique<MockMessageSerializer>());
    }

    void TearDown() override
    {
        delete mHandler;
        mHandler = nullptr;
    }
protected:
    QJsonObject createValidRequest(const QString& method = "testMethod",
                                  const QJsonValue& params = QJsonValue(),
                                  const QVariant& id = QVariant(1));
    QJsonObject createValidNotification(const QString& method = "testNotification",
                                       const QJsonValue& params = QJsonValue());

protected:
    JsonRpcHandlerImpl* mHandler;
};

TEST_F(TestJsonRpcHandlerImpl, DefaultConstructor)
{
    JsonRpcHandlerImpl handler;
    // Batch processing is no longer supported, no specific expectation needed
    SUCCEED();
}

TEST_F(TestJsonRpcHandlerImpl, ParseValidRequest)
{
    auto mockParser = std::make_unique<NiceMock<MockMessageParser>>();
    auto mockSerializer = std::make_unique<NiceMock<MockMessageSerializer>>();
    
    // Setup mock expectations
    QJsonObject validRequest = createValidRequest();
    EXPECT_CALL(*mockParser, validateMessage(_)).WillOnce(Return(true));
    EXPECT_CALL(*mockParser, parseMethodName(_)).WillOnce(Return("testMethod"));
    EXPECT_CALL(*mockParser, parseParameters(_)).WillOnce(Return(QJsonObject()));
    EXPECT_CALL(*mockParser, isNotification(_)).WillOnce(Return(false));
    
    QJsonObject successResponse;
    successResponse["result"] = "success";
    EXPECT_CALL(*mockSerializer, serializeSuccessResponse(_, _)).WillOnce(Return(successResponse));
    
    mHandler->setMessageParser(std::move(mockParser));
    mHandler->setMessageSerializer(std::move(mockSerializer));
    
    QByteArray requestData = QJsonDocument(validRequest).toJson();
    QJsonObject response = mHandler->parseRequest(requestData);
    
    EXPECT_FALSE(response.isEmpty());
    EXPECT_TRUE(response.contains("result"));
}

TEST_F(TestJsonRpcHandlerImpl, ParseInvalidJson)
{
    auto mockSerializer = std::make_unique<NiceMock<MockMessageSerializer>>();
    
    QJsonObject expectedErrorResponse;
    QJsonObject errorObj;
    errorObj["code"] = -32700;
    errorObj["message"] = "Parse error";
    expectedErrorResponse["error"] = errorObj;
    
    EXPECT_CALL(*mockSerializer, serializeErrorResponse(_, -32700, _))
        .WillOnce(Return(expectedErrorResponse));
    
    mHandler->setMessageSerializer(std::move(mockSerializer));
    
    QByteArray invalidJson = "{invalid json";
    QJsonObject response = mHandler->parseRequest(invalidJson);
    
    EXPECT_FALSE(response.isEmpty());
    EXPECT_TRUE(response.contains("error"));
    
    QJsonObject error = response["error"].toObject();
    EXPECT_EQ(error["code"].toInt(), -32700); // Parse error
}

TEST_F(TestJsonRpcHandlerImpl, ParseEmptyData)
{
    auto mockSerializer = std::make_unique<NiceMock<MockMessageSerializer>>();
    
    QJsonObject expectedErrorResponse;
    QJsonObject errorObj;
    errorObj["code"] = -32700;
    errorObj["message"] = "Parse error";
    expectedErrorResponse["error"] = errorObj;
    
    EXPECT_CALL(*mockSerializer, serializeErrorResponse(_, -32700, _))
        .WillOnce(Return(expectedErrorResponse));
    
    mHandler->setMessageSerializer(std::move(mockSerializer));
    
    QByteArray emptyData;
    QJsonObject response = mHandler->parseRequest(emptyData);
    
    EXPECT_FALSE(response.isEmpty());
    EXPECT_TRUE(response.contains("error"));
    
    QJsonObject error = response["error"].toObject();
    EXPECT_EQ(error["code"].toInt(), -32700); // Parse error
}

TEST_F(TestJsonRpcHandlerImpl, ProcessValidRequest)
{
    auto mockParser = std::make_unique<NiceMock<MockMessageParser>>();
    auto mockSerializer = std::make_unique<NiceMock<MockMessageSerializer>>();
    
    QJsonObject request = createValidRequest();
    QByteArray requestData = QJsonDocument(request).toJson();
    
    EXPECT_CALL(*mockParser, validateMessage(_)).WillOnce(Return(true));
    EXPECT_CALL(*mockParser, parseMethodName(_)).WillOnce(Return("testMethod"));
    EXPECT_CALL(*mockParser, parseParameters(_)).WillOnce(Return(QJsonObject()));
    EXPECT_CALL(*mockParser, isNotification(_)).WillOnce(Return(false));
    
    QJsonObject successResponse;
    successResponse["result"] = "success";
    EXPECT_CALL(*mockSerializer, serializeSuccessResponse(_, _)).WillOnce(Return(successResponse));
    
    mHandler->setMessageParser(std::move(mockParser));
    mHandler->setMessageSerializer(std::move(mockSerializer));
    
    QJsonObject response = mHandler->parseRequest(requestData);
    
    EXPECT_FALSE(response.isEmpty());
    EXPECT_TRUE(response.contains("result"));
}

TEST_F(TestJsonRpcHandlerImpl, ProcessNotificationRequest)
{
    auto mockParser = std::make_unique<NiceMock<MockMessageParser>>();
    
    QJsonObject notification = createValidRequest("testNotification", QJsonValue(), QJsonValue());
    QByteArray notificationData = QJsonDocument(notification).toJson();
    
    EXPECT_CALL(*mockParser, validateMessage(_)).WillOnce(Return(true));
    EXPECT_CALL(*mockParser, isNotification(_)).WillOnce(Return(true));
    
    mHandler->setMessageParser(std::move(mockParser));
    
    QJsonObject response = mHandler->parseRequest(notificationData);
    
    // Notifications should return empty response
    EXPECT_TRUE(response.isEmpty());
}

// Batch validation is tested indirectly through handleBatchRequest and parseRequest methods

// Helper methods
QJsonObject TestJsonRpcHandlerImpl::createValidRequest(const QString& method, 
                                                      const QJsonValue& params,
                                                      const QVariant& id)
{
    QJsonObject request;
    request["jsonrpc"] = "2.0";
    request["method"] = method;
    
    if (!params.isNull()) {
        request["params"] = params;
    }
    
    if (id.isValid() && !id.isNull()) {
        request["id"] = QJsonValue::fromVariant(id);
    }
    
    return request;
}

QJsonObject TestJsonRpcHandlerImpl::createValidNotification(const QString& method,
                                                           const QJsonValue& params)
{
    return createValidRequest(method, params, QVariant());
}
